package com.niiwoo.civet.trade.service.local.creditor;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.rpc.RpcContext;
import com.google.common.collect.Lists;
import com.niiwoo.civet.trade.dao.entity.CreditorSaleBatch;
import com.niiwoo.civet.trade.dao.entity.CreditorSaleDetail;
import com.niiwoo.civet.trade.dao.entity.InvestorCreditor;
import com.niiwoo.civet.trade.dao.entity.Project;
import com.niiwoo.civet.trade.dao.entity.ProjectInvestOrder;
import com.niiwoo.civet.trade.dao.mapper.CreditorSaleDetailMapperExt;
import com.niiwoo.civet.trade.dao.mapper.InvestorCreditorMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectMapperExt;
import com.niiwoo.civet.trade.dto.request.creditor.TradableInvestOrderRequestDTO;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.local.configure.TradeConfigLocalService;
import com.niiwoo.civet.trade.utils.RepaymentUtil;
import com.niiwoo.civet.user.dto.request.SimpleOrgInfo;
import com.niiwoo.civet.user.dto.request.UserLetterRequestDTO;
import com.niiwoo.civet.user.dto.response.UserIdentityInfoResponseDTO;
import com.niiwoo.civet.user.enums.MessageTemplateKeyEnum;
import com.niiwoo.civet.user.enums.SMSTemplateKeyEnum;
import com.niiwoo.civet.user.enums.UserLetterTypeEnum;
import com.niiwoo.civet.user.service.OrganizationDubboService;
import com.niiwoo.civet.user.service.SendSmsDubboService;
import com.niiwoo.civet.user.service.UserIdentityDubboService;
import com.niiwoo.civet.user.service.UserLetterDubboService;
import com.niiwoo.tripod.provider.exception.BizException;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class TradableInvestOrderService {
	@Autowired
    private TradeConfigLocalService tradeConfigLocalService;
	
	@Autowired
	private InvestorCreditorMapperExt investorCreditorMapperExt;
	
	@Autowired
    private ProjectMapperExt projectMapperExt;
	
	@Autowired
	private CreditorSaleDetailMapperExt creditorSaleDetailMapperExt;

	@Reference(version = "1.0.0")
    private UserLetterDubboService userLetterDubboService;

	@Reference(version = "1.0.0")
    private UserIdentityDubboService userIdentityDubboService;

	@Reference(version = "1.0.0")
    private OrganizationDubboService organizationDubboService;

	@Reference(version = "1.0.0")
    private SendSmsDubboService sendSmsDubboService;

	/**
	 * 封装对应查询条件
	 * @param request
	 */
	public void buildTradableInvestOrderQueryCondition(TradableInvestOrderRequestDTO request) {
        Map<String, String> map = getTradableInvestOrderLimitCondition();
        
        if (map != null) {
        	if (map.get(TradeConfigEnum.DEBT_MIN_HAND_PERIOD.getConfigKey()) != null) //已收回款期数
        		request.setMinRepaymentPriod(Integer.valueOf(map.get(TradeConfigEnum.DEBT_MIN_HAND_PERIOD.getConfigKey())));
        	if (map.get(TradeConfigEnum.DEBT_MIN_REMAIN_PERIOD.getConfigKey()) != null) { //最少剩余回款期数
        		request.setMinPaymentPriod(Integer.valueOf(map.get(TradeConfigEnum.DEBT_MIN_REMAIN_PERIOD.getConfigKey())));
        		request.setMinPaymentPriod(request.getMinPaymentPriod() - 1);
        	}
        	if (map.get(TradeConfigEnum.DEBT_LIMIT_TRANSFER_DAYS.getConfigKey()) != null) //限制债权转让时间
        		request.setMinIntervalDays(Integer.valueOf(map.get(TradeConfigEnum.DEBT_LIMIT_TRANSFER_DAYS.getConfigKey())));
        	if (map.get(TradeConfigEnum.DEBT_MIN_TRANSFER_AMOUNT.getConfigKey()) != null) //债权最低可转让金额
        		request.setMinTradableAmount(new BigDecimal(map.get(TradeConfigEnum.DEBT_MIN_TRANSFER_AMOUNT.getConfigKey())));
        	if (map.get(TradeConfigEnum.DEBT_MAX_TRANSFER_COUNT.getConfigKey()) != null) //转让中债权最大数量
        		request.setMaxTransferCount(Integer.valueOf(map.get(TradeConfigEnum.DEBT_MAX_TRANSFER_COUNT.getConfigKey())));
        	if (map.get(TradeConfigEnum.DEBT_LIMIT_TRANSFER_TIMES.getConfigKey()) != null) //转让中债权最大转让次数
        		request.setMaxTransferTimes(Integer.valueOf(map.get(TradeConfigEnum.DEBT_LIMIT_TRANSFER_TIMES.getConfigKey())));
        }
        
        if (request.getMinIntervalDays() != null) {
        	request.setMinReceivedDate(getMinReceivedDate(request.getMinIntervalDays()));
        }
        
        DateTime dt = new DateTime(new Date());
        dt = dt.withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0);
        request.setCurrentDate(dt.toDate());
	}
	
	/**
	 * 获取债权相关配置
	 * @param request
	 */
	public Map<String, String> getTradableInvestOrderLimitCondition() {
		List<TradeConfigEnum> enumList =new ArrayList<TradeConfigEnum>();
		enumList.add(TradeConfigEnum.DEBT_ON_OFF); //债权转让开关(总开关)；0-关，1-开
		enumList.add(TradeConfigEnum.DEBT_LAUNCH_ON_OFF); //债权转让业务发起开关 0-关 1-开
		enumList.add(TradeConfigEnum.DEBT_APPLY_TIME_BEGIN); //申请债权转让时间开始
		enumList.add(TradeConfigEnum.DEBT_APPLY_TIME_END); //申请债权转让时间结束
        enumList.add(TradeConfigEnum.DEBT_MIN_HAND_PERIOD); //已收回款期数
        enumList.add(TradeConfigEnum.DEBT_MIN_REMAIN_PERIOD); //最少剩余回款期数
        enumList.add(TradeConfigEnum.DEBT_LIMIT_TRANSFER_DAYS); //限制债权转让时间
        enumList.add(TradeConfigEnum.DEBT_TRANSFER_TIME_LIMIT); //债权转让购买时效
        enumList.add(TradeConfigEnum.DEBT_MIN_TRANSFER_AMOUNT); //债权最低可转让金额
        enumList.add(TradeConfigEnum.DEBT_MAX_TRANSFER_COUNT); //转让中债权最大数量
        enumList.add(TradeConfigEnum.DEBT_LIMIT_TRANSFER_TIMES); //单个债权限转次数
        enumList.add(TradeConfigEnum.DEBT_TRANSFER_TAG_PERIOD); //可转让标示配置
        
        enumList.add(TradeConfigEnum.CREDITOR_RATE_PROMPT_TEXT); //转让费率弹窗文案
        enumList.add(TradeConfigEnum.CREDITOR_QUALIFICATION_PROMPT_TEXT); //可转让债权条件弹窗文案
        
        return tradeConfigLocalService.selectTradeConfigByEmuns(enumList);
	}
	
	/**
	 * 计算可交易金额（待收本金+当期应收利息）
	 * @param amount 待收本金
	 * @param intrest 当期利息
	 * @param receivedDate 下期回款日
	 * @return
	 */
	public BigDecimal calcTradableAmount(BigDecimal amount, BigDecimal intrest, Date receivedDate) {
		if (intrest == null) return amount;
		
		DateTime now = new DateTime();
		DateTime currentPriodReceivedDate = now.withDate(new LocalDate(receivedDate));
		DateTime prePriodReceivedDate = currentPriodReceivedDate.plusMonths(-1).plusDays(1); //不包括上期回款日
		
		if (prePriodReceivedDate.isAfterNow())
			return amount;
		else {
			int currentPriodRemainDays = Days.daysBetween(now, currentPriodReceivedDate).getDays();
			int currentPriodInterestDays = Days.daysBetween(now, prePriodReceivedDate).getDays();
			int intrestDays = Days.daysBetween(prePriodReceivedDate, currentPriodReceivedDate).getDays();
			
			BigDecimal remainIntrest = intrest.multiply(new BigDecimal(currentPriodRemainDays)).divide(new BigDecimal(intrestDays)).setScale(2, RoundingMode.HALF_EVEN);
			BigDecimal receivableIntrest = intrest.multiply(new BigDecimal(currentPriodInterestDays)).divide(new BigDecimal(intrestDays)).setScale(2, RoundingMode.HALF_EVEN);
			
			return amount.add(receivableIntrest).setScale(2, RoundingMode.HALF_EVEN);
		}
	}

	/**
	 * 获取总剩余天数
	 * @param currentPriod
	 * @param dealine
	 * @param receivedDate
	 * @return
	 */
	public Integer calcTotalRemainDays(Integer currentPriod, Integer dealine, Date receivedDate) {
		DateTime now = new DateTime();
		DateTime currentPriodReceivedDate = now.withDate(new LocalDate(receivedDate));
		DateTime prePriodReceivedDate = currentPriodReceivedDate.plusMonths(-1).plusDays(1); //不包括上期回款日
		
		int remainMonths = dealine - currentPriod;
		DateTime lastRepaymentDate = currentPriodReceivedDate.plusMonths(remainMonths);
		
		if (prePriodReceivedDate.isAfterNow()) {
			return Days.daysBetween(currentPriodReceivedDate, lastRepaymentDate).getDays();
		} else {
			return Days.daysBetween(now, lastRepaymentDate).getDays();
		}
	}
	
	/**
	 * 获取剩余天数
	 * @param receivedDate
	 * @return
	 */
	public Integer calcCurrentPriodRemainDays(Date receivedDate, Date lastPeriodReceivedDate, Long projectId) {
		DateTime now = new DateTime();
		DateTime currentPriodReceivedDate = now.withDate(new LocalDate(receivedDate));
		
		DateTime prePriodReceivedDate = null;
		if (lastPeriodReceivedDate != null) {
			prePriodReceivedDate = now.withDate(new LocalDate(lastPeriodReceivedDate)).plusDays(1); //不包括上期回款日
		} else {
			Project project = projectMapperExt.selectByPrimaryKey(projectId);
			prePriodReceivedDate = now.withDate(new LocalDate(project.getFullSuccessTime()));
		}
		
		if (prePriodReceivedDate.isAfterNow())
			return Days.daysBetween(now, prePriodReceivedDate).getDays();
		else 
			return Days.daysBetween(now, currentPriodReceivedDate).getDays();
	}
	
	/**
	 * 计算最小的结算日期
	 * @param minIntervalDays
	 * @return
	 */
	public Date getMinReceivedDate(int minIntervalDays) {
		DateTime dt = new DateTime();
		return dt.plusDays(minIntervalDays + 1).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0).toDate();
	}

	/**
	 * 获取用户所有剩余期限列表
	 * @param userId
	 * @return
	 */
	public List<Integer> findUserTradableInvestOrderActivePriod(String userId) {
		TradableInvestOrderRequestDTO request = new TradableInvestOrderRequestDTO();
		request.setUserId(userId);
		buildTradableInvestOrderQueryCondition(request);
		return investorCreditorMapperExt.findUserTradableInvestOrderActivePriod(request);
	}
	
	/**
	 * 债转单金额计算
	 * @param detail
	 */
	public void reCalcAmount(CreditorSaleDetail detail) {
		int changeDays = 0;
		Date currentTime = new Date();
		Date endTime = detail.getEndTime();
		Date expireTime = detail.getExpireTime();
		//Date successTime = detail.getSuccessTime();
		Date createTime = detail.getCreateTime();
		
		switch (detail.getStatus()) {//状态：0-转让申请中，1-转让中，2-认购中，3-交易处理中（债权转让）4-转让成功，5-已结束(失败)
		case 0: //0-转让申请中
		case 1: //1-转让中
		case 2: //2-认购中
		case 3: //3-交易处理中（债权转让）
			changeDays = RepaymentUtil.getOverdueDay(createTime, currentTime);
			break;
		case 4: //4-转让成功
			// changeDays = RepaymentUtil.getOverdueDay(createTime, successTime);
			// break;
			return;
		case 5: //5-已结束(失败)
			switch (detail.getEndType()) {//结束类型：0-初始，1-用户撤销，2-已过期，3-用户还款,4-其他
			case 2:
				changeDays = RepaymentUtil.getOverdueDay(createTime, expireTime);
				break;
			case 0:
			case 1:
			case 3:
			default:
				changeDays = RepaymentUtil.getOverdueDay(createTime, endTime);
				break;
			}
			break;
		default:
			changeDays = RepaymentUtil.getOverdueDay(createTime, endTime);
			break;
		}

		BigDecimal sellingInterest = new BigDecimal(0);
		BigDecimal oldOffAmount = detail.getOffAmount();
		BigDecimal offReceivableInterest = new BigDecimal(0);
		if (changeDays > 0) {
			// 获取原始的投资订单信息
			InvestorCreditor investorCreditor = investorCreditorMapperExt.queryInvestorCreditorByInvestOrderId(detail.getInvestOrderId());
			// 应收利息天数
			int interestDays = RepaymentUtil.getOverdueDay(investorCreditor.getLastPeriodReceivedDate(), currentTime);
			if (interestDays > 0) interestDays -= 1; //去除当前日期
			// 应收利息 = 每日利息 * 应收利息天数
			BigDecimal receivableInterest = detail.getCurrentInterestForDay().multiply(new BigDecimal(interestDays)).setScale(2, RoundingMode.HALF_EVEN);
			// 原始债权金额
			BigDecimal originalAmount = investorCreditor.getCapital().subtract(investorCreditor.getReceivedCapital()).add(receivableInterest).setScale(2, RoundingMode.HALF_EVEN);
			// 最新的转让价格 = 原始债权金额 *（1 - 让利比例）
			BigDecimal newSaleAmount = originalAmount.multiply(new BigDecimal(1).subtract(detail.getOffPercent())).setScale(2, RoundingMode.HALF_EVEN);
			// 让利后的变更利息
			sellingInterest = newSaleAmount.subtract(detail.getSaleAmount()).setScale(2, RoundingMode.HALF_EVEN);
			
			// 计算申请时的让利金额
			int oldInterestDays = RepaymentUtil.getOverdueDay(investorCreditor.getLastPeriodReceivedDate(), detail.getCreateTime());
			if (oldInterestDays > 0) oldInterestDays -= 1; //去除当前日期
			BigDecimal oldReceivableInterest = detail.getCurrentInterestForDay().multiply(new BigDecimal(oldInterestDays)).setScale(2, RoundingMode.HALF_EVEN);
			BigDecimal oldOriginalAmount = investorCreditor.getCapital().subtract(investorCreditor.getReceivedCapital()).add(oldReceivableInterest).setScale(2, RoundingMode.HALF_EVEN);
			oldOffAmount = oldOriginalAmount.multiply(detail.getOffPercent()).setScale(2, RoundingMode.HALF_EVEN); //防止在债权认购时对让利金额字段进行呢重写
		
			// 变更利息让利金额 = (当前应收利息 + 申请时应收利息) * 让利比例
			offReceivableInterest = receivableInterest.subtract(oldReceivableInterest).multiply(detail.getOffPercent()).setScale(2, RoundingMode.HALF_EVEN);
		}

		// 变更利息服务费 = 让利后的变更利息  * 转让服务费费率
		BigDecimal sellingExpenseAmount = sellingInterest.multiply(detail.getExpenseRate()).setScale(2, RoundingMode.HALF_EVEN);

		// 实际到账金额 = 申请时转让价格 - 申请时转让服务费 + 让利后的变更利息- 变更利息服务费  (申请时的转让价格是不包含让利金额的)
		BigDecimal arrivalAmount = detail.getSaleAmount().subtract(detail.getExpenseAmount()).add(sellingInterest).subtract(sellingExpenseAmount).setScale(2, RoundingMode.HALF_EVEN);
		// 让利金额 = 申请时让利金额 + 变更利息让利金额
		BigDecimal offAmount = oldOffAmount.add(offReceivableInterest).setScale(2, RoundingMode.HALF_EVEN);

		detail.setArrivalAmount(arrivalAmount); //实际到账金额
		detail.setOffAmount(offAmount); //让利金额
		detail.setSellingInterest(sellingInterest); // 出让期间利息
		detail.setSellingExpenseAmount(sellingExpenseAmount); // 出让期间手续费
	}
	
	/**
	 * 验证债权出让全局参数配置
	 */
	public void validateGlobalConfiguration() {
		Map<String, String> tradeConfigMap = getTradableInvestOrderLimitCondition();
		
		// 是否开启债权转让 
		String debtOnOff = MapUtils.getString(tradeConfigMap, TradeConfigEnum.DEBT_ON_OFF.getConfigKey(), "0");
		String debtBusOnOff = MapUtils.getString(tradeConfigMap, TradeConfigEnum.DEBT_LAUNCH_ON_OFF.getConfigKey(), "0");
		if ("0".equals(debtOnOff) || "0".equals(debtBusOnOff)) {
			throw new BizException("TRD1000001");
		}
		
		// 是否开启时间内
		DateTime currentDate = new DateTime();
		String startTime = MapUtils.getString(tradeConfigMap, TradeConfigEnum.DEBT_APPLY_TIME_BEGIN.getConfigKey(), "08:00");
		String endTime = MapUtils.getString(tradeConfigMap, TradeConfigEnum.DEBT_APPLY_TIME_END.getConfigKey(), "22:00");
		DateTime dateTimeStart = new DateTime(currentDate.getYear(), currentDate.getMonthOfYear(), currentDate.getDayOfMonth(), Integer.parseInt(startTime.split(":")[0]),
				Integer.parseInt(startTime.split(":")[1]), 0);
		DateTime dateTimeEnd = new DateTime(currentDate.getYear(), currentDate.getMonthOfYear(),
				currentDate.getDayOfMonth(), Integer.parseInt(endTime.split(":")[0]), Integer.parseInt(endTime.split(":")[1]), 0);
        if (currentDate.getMillis() < dateTimeStart.getMillis() || currentDate.getMillis() > dateTimeEnd.getMillis()){
			throw new BizException("TRD1000002", startTime, endTime);
        }
	}

	/**
	 * 债转申请成功通知和push
	 * @param batch
	 */
	public void sendDebtApplySuccessMessage(CreditorSaleBatch batch) {
		if (batch == null) {
			log.error("参数为空！");
			return;
		}

		log.debug("发送债转申请成功通知， userId={}",batch.getSaleUserId());

        UserLetterRequestDTO req = new UserLetterRequestDTO();
        req.setToUserId(batch.getSaleUserId());
        req.setUserLetterTypeEnum(UserLetterTypeEnum.LETTER_AND_JPUSH); //通知+推送
        req.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.DEBT_TRANSFEROR_APPLY_SUCCESS);
        req.setJpushTemplateKeyEnum(MessageTemplateKeyEnum.JPushTemplateKeyEnum.DEBT_TRANSFEROR_APPLY_SUCCESS);

        Map<String, String> map = getTradableInvestOrderLimitCondition();

        req.setLetterTemplateParamList(Lists.newArrayList(batch.getSaleAmount(), batch.getDetailCount(), map.get("debt.transfer.time.limit")));
        req.setJpushTemplateParamList(Lists.newArrayList(batch.getSaleAmount(), batch.getDetailCount(), map.get("debt.transfer.time.limit")));
		RpcContext.getContext().asyncCall(() -> userLetterDubboService.pushLetter(req));
    }

	/**
	 * 债转成功通知和push
	 * @param detail
	 */
	public void sendDebtTransferSuccessMessage(ProjectInvestOrder investOrder) {
		if (investOrder == null) {
			log.error("参数为空！");
			return;
		}

		CreditorSaleDetail detail = creditorSaleDetailMapperExt.selectByPrimaryKeyAndSaleUserId(investOrder.getCreditorSaleDetailId(), investOrder.getCreditorSaleUserId());
		if (detail == null) {
			log.error("债权明细为空，creditorSaleDetailId={}, userId={}", investOrder.getCreditorSaleDetailId(), investOrder.getCreditorSaleUserId());
			return;
		}

		log.debug("发送债转成功通知， userId={}",investOrder.getCreditorSaleUserId());

		//转让人
        UserLetterRequestDTO req = new UserLetterRequestDTO();
        req.setToUserId(detail.getUserId());
        req.setUserLetterTypeEnum(UserLetterTypeEnum.LETTER_AND_JPUSH); //通知+推送
        req.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.DEBT_TRANSFEROR_TRANSFER_SUCCESS);
        req.setJpushTemplateKeyEnum(MessageTemplateKeyEnum.JPushTemplateKeyEnum.DEBT_TRANSFEROR_TRANSFER_SUCCESS);
        req.setLetterTemplateParamList(Lists.newArrayList(detail.getSaleAmount(), detail.getExpenseAmount(), detail.getArrivalAmount()));
        req.setJpushTemplateParamList(Lists.newArrayList(detail.getSaleAmount(), detail.getExpenseAmount(), detail.getArrivalAmount()));
		RpcContext.getContext().asyncCall(() -> userLetterDubboService.pushLetter(req));

		// 短信
		sendSmsDubboService.sendSmsByUserId(detail.getUserId(), SMSTemplateKeyEnum.DEBT_TRANSFEROR_TRANSFER_SUCCESS.getKey(), Lists.newArrayList(detail.getSaleAmount().toPlainString(), detail.getExpenseAmount().toPlainString(), detail.getArrivalAmount().toPlainString()));

		//受让人
		UserLetterRequestDTO assigneeReq = new UserLetterRequestDTO();
		assigneeReq.setToUserId(investOrder.getUserId());
		assigneeReq.setUserLetterTypeEnum(UserLetterTypeEnum.LETTER_AND_JPUSH); //通知+推送
		assigneeReq.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.DEBT_ASSIGNEE_BUY_SUCCESS);
		assigneeReq.setJpushTemplateKeyEnum(MessageTemplateKeyEnum.JPushTemplateKeyEnum.DEBT_ASSIGNEE_BUY_SUCCESS);
		//债权价格=实际到账金额+转让手续费
		BigDecimal debtAmount = detail.getArrivalAmount().add(detail.getExpenseAmount()).setScale(2, RoundingMode.HALF_EVEN);
		//债权收益=逾期利息-出让期间产生的利息+让利金额
		BigDecimal debtInterest = detail.getInterest().subtract(detail.getSellingInterest()).add(detail.getOffAmount()).setScale(2, RoundingMode.HALF_EVEN);
		assigneeReq.setLetterTemplateParamList(Lists.newArrayList(detail.getDeadline(), toHundredPercentByNumberFormat(detail.getBorrowRate()), debtAmount, debtInterest));
		assigneeReq.setJpushTemplateParamList(Lists.newArrayList(detail.getDeadline(), toHundredPercentByNumberFormat(detail.getBorrowRate()), debtAmount, debtInterest));
		RpcContext.getContext().asyncCall(() -> userLetterDubboService.pushLetter(assigneeReq));

		//借款人
		Project project = projectMapperExt.selectByPrimaryKey(detail.getProjectId());

		UserLetterRequestDTO borrowerReq = new UserLetterRequestDTO();
		borrowerReq.setToUserId(project.getBorrowUserId());
		borrowerReq.setUserLetterTypeEnum(UserLetterTypeEnum.LETTER_AND_JPUSH); //通知+推送
		borrowerReq.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.DEBT_BORROWER_NOTIFY);
		borrowerReq.setJpushTemplateKeyEnum(MessageTemplateKeyEnum.JPushTemplateKeyEnum.DEBT_BORROWER_NOTIFY);

		String assigneeName = "";
		if (investOrder.getInvestorType() == 1) { //1-个人
			UserIdentityInfoResponseDTO user = userIdentityDubboService.get(investOrder.getUserId());
			assigneeName = user == null ? "" : user.getName();
		} else { //2-企业
			SimpleOrgInfo org = organizationDubboService.getByOrgId(investOrder.getUserId());
			assigneeName = org == null ? "" : org.getOrganizationName();
		}

		borrowerReq.setLetterTemplateParamList(Lists.newArrayList(project == null ? "" : project.getContractAmount(), detail.getShare(), detail.getRealName(), assigneeName, detail.getProjectId()));
		borrowerReq.setJpushTemplateParamList(Lists.newArrayList(project == null ? "" : project.getContractAmount(), detail.getShare(), detail.getRealName(), assigneeName, detail.getProjectId()));
		RpcContext.getContext().asyncCall(() -> userLetterDubboService.pushLetter(borrowerReq));
    }

	@SuppressWarnings("unused")
	@Deprecated
	private static String toHundredPercentByDecimalFormat(BigDecimal d) {
		// 弃用；会导致多余的0出来，例如0.09 -> 9.00%
		DecimalFormat df = new DecimalFormat("0.00%");
		return df.format(d);
	}

	private String toHundredPercentByNumberFormat(BigDecimal d) {
		NumberFormat percent = NumberFormat.getPercentInstance();
		percent.setMaximumFractionDigits(2);
		return percent.format(d.doubleValue());
	}

	/**
	 * 债转失败通知和push
	 * @param detail
	 */
	public void sendDebtTransferFailureMessage(CreditorSaleDetail detail) {
		if (detail == null) {
			log.error("参数为空！");
			return;
		}

		log.debug("发送债转失败通知， userId={}",detail.getUserId());

        UserLetterRequestDTO req = new UserLetterRequestDTO();
        req.setToUserId(detail.getUserId());
        req.setUserLetterTypeEnum(UserLetterTypeEnum.LETTER_AND_JPUSH); //通知+推送

        switch (detail.getEndType()) {//结束类型：0-初始，1-用户撤销，2-已过期，3-用户还款,4-其他
		case 1: //1-用户撤销
			req.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.DEBT_TRANSFEROR_TRANSFER_FAIL_CANCEL);
			req.setJpushTemplateKeyEnum(MessageTemplateKeyEnum.JPushTemplateKeyEnum.DEBT_TRANSFEROR_TRANSFER_FAIL_CANCEL);
			req.setLetterTemplateParamList(Lists.newArrayList(detail.getSaleAmount()));
			req.setJpushTemplateParamList(Lists.newArrayList(detail.getSaleAmount()));
			break;
		case 2: //2-已过期
			Map<String, String> map = getTradableInvestOrderLimitCondition();

			req.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.DEBT_TRANSFEROR_TRANSFER_FAIL_OVERTIME);
			req.setJpushTemplateKeyEnum(MessageTemplateKeyEnum.JPushTemplateKeyEnum.DEBT_TRANSFEROR_TRANSFER_FAIL_OVERTIME);
			req.setLetterTemplateParamList(Lists.newArrayList(detail.getSaleAmount(), map.get("debt.transfer.time.limit")));
			req.setJpushTemplateParamList(Lists.newArrayList(detail.getSaleAmount(), map.get("debt.transfer.time.limit")));
			break;
		case 3: //3-用户还款
			req.setLetterTemplateEnum(MessageTemplateKeyEnum.LetterTemplateKeyEnum.DEBT_TRANSFEROR_TRANSFER_FAIL_REPAYMENT);
			req.setJpushTemplateKeyEnum(MessageTemplateKeyEnum.JPushTemplateKeyEnum.DEBT_TRANSFEROR_TRANSFER_FAIL_REPAYMENT);
			req.setLetterTemplateParamList(Lists.newArrayList(detail.getSaleAmount()));
			req.setJpushTemplateParamList(Lists.newArrayList(detail.getSaleAmount()));
			break;
		case 4: //4-其他
		case 0: //0-初始
		default:
			log.error("错误的状态，id={}, endType={}", detail.getId(), detail.getEndType());
			return;
		}

		RpcContext.getContext().asyncCall(() -> userLetterDubboService.pushLetter(req));

		// 短信，借款人还款情况下发送短信
		if (detail.getEndType() == 3) {
			sendSmsDubboService.sendSmsByUserId(detail.getUserId(), SMSTemplateKeyEnum.DEBT_TRANSFEROR_TRANSFER_FAIL_REPAYMENT.getKey(), Lists.newArrayList(detail.getSaleAmount().toPlainString()));
		}
    }

}
